added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / tools / nmake / nmake.cpp
blob995c2d4450d308cb7ab649ac1f7d423147c4c9e2
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
14 // ==--==
15 // NMAKE.C - main module
17 // Purpose:
18 // This is the main module of nmake
20 #include "precomp.h"
21 #ifdef _MSC_VER
22 #pragma hdrstop
23 #endif
25 #include "verstamp.h"
26 #include <palstartup.h>
28 int readEnvironmentVars(void);
29 void readMakeFiles(void);
30 void useDefaultMakefile(void);
31 BOOL filename(const char*, char**);
32 BOOL PALAPI chkPrecious(DWORD CtrlType);
33 UCHAR isPrecious(char*);
34 void removeTrailChars(char *);
36 void usage (void);
38 char *makeStr; // this make invocation name
40 UCHAR okToDelete; // do not del unless exec'ing cmd
42 #ifdef _M_IX86
43 UCHAR fRunningUnderChicago;
45 extern UCHAR FIsChicago(void);
46 #endif
48 const char * const builtInTarg[] = {
49 ".SUFFIXES",
50 ".c.obj",
51 ".c.exe",
52 ".cpp.obj",
53 ".cpp.exe",
54 ".cxx.obj",
55 ".cxx.exe",
56 #if defined(_M_IX86) || defined(_M_MRX000)
57 ".asm.obj",
58 ".asm.exe",
59 #endif
60 #if !defined(_M_IX86)
61 ".s.obj",
62 #endif
63 ".bas.obj",
64 ".cbl.obj",
65 ".cbl.exe",
66 ".f.obj",
67 ".f.exe",
68 ".f90.obj",
69 ".f90.exe",
70 ".for.obj",
71 ".for.exe",
72 ".pas.obj",
73 ".pas.exe",
74 ".rc.res",
75 NULL
78 const char * const bltInCmd0[] = {
79 ":",
80 ".exe",
81 ".obj",
82 #if defined(_M_IX86) || defined(_M_MRX000)
83 ".asm",
84 #endif
85 #if !defined(_M_IX86)
86 ".s",
87 #endif
88 ".c",
89 ".cpp",
90 ".cxx",
91 ".bas",
92 ".cbl",
93 ".f",
94 ".f90",
95 ".for",
96 ".pas",
97 ".res",
98 ".rc",
99 NULL
102 // Single colon (":") specifies ordinary rules
103 // Double colon ("::") specifies batch rules
104 const char * const bltInCmd1[] = {":", "$(CC) $(CFLAGS) /c $<", NULL};
105 const char * const bltInCmd2[] = {":", "$(CC) $(CFLAGS) $<", NULL};
106 const char * const bltInCmd3[] = {":", "$(CPP) $(CPPFLAGS) /c $<", NULL};
107 const char * const bltInCmd4[] = {":", "$(CPP) $(CPPFLAGS) $<", NULL};
108 const char * const bltInCmd5[] = {":", "$(CXX) $(CXXFLAGS) /c $<", NULL};
109 const char * const bltInCmd6[] = {":", "$(CXX) $(CXXFLAGS) $<", NULL};
110 #if defined(_M_IX86) || defined(_M_MRX000)
111 const char * const bltInCmd7[] = {":", "$(AS) $(AFLAGS) /c $*.asm", NULL};
112 const char * const bltInCmd8[] = {":", "$(AS) $(AFLAGS) $*.asm", NULL};
113 #endif
114 #if !defined(_M_IX86)
115 const char * const bltInCmd9[] = {":", "$(AS) $(AFLAGS) $*.s", NULL};
116 #endif
117 const char * const bltInCmd10[] = {":", "$(BC) $(BFLAGS) $*.bas;", NULL};
118 const char * const bltInCmd11[] = {":", "$(COBOL) $(COBFLAGS) $*.cbl;", NULL};
119 const char * const bltInCmd12[] = {":", "$(COBOL) $(COBFLAGS) $*.cbl, $*.exe;", NULL};
120 const char * const bltInCmd13[] = {":", "$(FOR) /c $(FFLAGS) $*.f", NULL};
121 const char * const bltInCmd14[] = {":", "$(FOR) $(FFLAGS) $*.f", NULL};
122 const char * const bltInCmd15[] = {":", "$(FOR) /c $(FFLAGS) $*.f90", NULL};
123 const char * const bltInCmd16[] = {":", "$(FOR) $(FFLAGS) $*.f90", NULL};
124 const char * const bltInCmd17[] = {":", "$(FOR) /c $(FFLAGS) $*.for", NULL};
125 const char * const bltInCmd18[] = {":", "$(FOR) $(FFLAGS) $*.for", NULL};
126 const char * const bltInCmd19[] = {":", "$(PASCAL) /c $(PFLAGS) $*.pas", NULL};
127 const char * const bltInCmd20[] = {":", "$(PASCAL) $(PFLAGS) $*.pas", NULL};
128 const char * const bltInCmd21[] = {":", "$(RC) $(RFLAGS) /r $*", NULL};
130 const char * const * const builtInCom[] = {
131 bltInCmd0,
132 bltInCmd1,
133 bltInCmd2,
134 bltInCmd3,
135 bltInCmd4,
136 bltInCmd5,
137 bltInCmd6,
138 #if defined(_M_IX86) || defined(_M_MRX000)
139 bltInCmd7,
140 bltInCmd8,
141 #endif
142 #if !defined(_M_IX86)
143 bltInCmd9,
144 #endif
145 bltInCmd10,
146 bltInCmd11,
147 bltInCmd12,
148 bltInCmd13,
149 bltInCmd14,
150 bltInCmd15,
151 bltInCmd16,
152 bltInCmd17,
153 bltInCmd18,
154 bltInCmd19,
155 bltInCmd20,
156 bltInCmd21,
157 NULL
160 // main
162 // actions: saves the initial global variables in a
163 // block. calls doMake() and then delTempScriptFiles()
165 int __cdecl
166 main(
167 int argc,
168 char **argv
171 int status; // returned by doMake
173 _pgmptr = argv[0];
175 #ifdef _M_IX86
176 fRunningUnderChicago = FIsChicago();
177 #endif
179 initCharmap();
181 initMacroTable(macroTable);
184 if (!makeStr) {
185 // extract file name
186 if (!filename(_pgmptr, &makeStr)) {
187 makeStr = "NMAKE";
191 // set up handler for .PRECIOUS the handler tries to remove the
192 // current target when control-C'd, unless it is "precious"
194 SetConsoleCtrlHandler(chkPrecious, TRUE);
196 status = doMake(argc, argv, NULL);
198 delScriptFiles();
200 if (!fSlashKStatus) {
201 status = 1; // error when slashK specified
204 #if !defined(NDEBUG)
205 printStats();
206 #endif
207 return status;
210 extern void endNameList(void);
211 extern void addItemToList(void);
212 extern void assignDependents(void);
213 extern void assignBuildCommands(void);
215 // loadBuiltInRules() -- Loads built in Rules to the NMAKE Tables
217 // Modifies:
218 // fInheritUserEnv -- is set to TRUE to inherit CC, AS
220 // Notes:
221 // Does this by calls to defineMacro(), which calls putMacro(). Since,
222 // fInheritUserEnv is set to TRUE, putMacro() will add to the Environment.
224 void
225 loadBuiltInRules(
226 void
229 const char *tempTarg;
230 const char * const *tempCom;
231 unsigned index;
232 char *macroName, *macroValue;
234 // We dynamically allocate CC and AS because they need to be freed in a
235 // recursive MAKE
237 macroName = makeString("CC");
238 macroValue = makeString("cl");
239 defineMacro(macroName, macroValue, 0);
240 macroName = makeString("CXX");
241 macroValue = makeString("cl");
242 defineMacro(macroName, macroValue, 0);
243 macroName = makeString("CPP");
244 macroValue = makeString("cl");
245 defineMacro(macroName, macroValue, 0);
246 macroName = makeString("AS");
248 macroValue = makeString("ml");
249 defineMacro(macroName, macroValue, 0);
250 macroName = makeString("BC");
251 macroValue = makeString("bc");
252 defineMacro(macroName, macroValue, 0);
253 macroName = makeString("COBOL");
254 macroValue = makeString("cobol");
255 defineMacro(macroName, macroValue, 0);
256 macroName = makeString("FOR");
257 macroValue = makeString("fl32");
258 defineMacro(macroName, macroValue, 0);
259 macroName = makeString("PASCAL");
260 macroValue = makeString("pl");
261 defineMacro(macroName, macroValue, 0);
262 macroName = makeString("RC");
263 macroValue = makeString("rc");
264 defineMacro(macroName, macroValue, 0);
265 macroName = makeString("_NMAKE_VER");
266 macroValue = makeString(VER_PRODUCTVERSION_STR);
267 defineMacro(macroName, macroValue, 0);
268 macroName = makeString("MAKE");
269 macroValue = makeString(makeStr);
270 // From environment so it won't get exported ; user can reset MAKE
272 defineMacro(macroName, macroValue, M_ENVIRONMENT_DEF|M_WARN_IF_RESET);
274 for (index = 0; (tempTarg = builtInTarg[index]); index++) {
275 name = makeString(tempTarg);
276 tempCom = builtInCom[index];
277 // tempCom should now contain a single or double colon
278 assert (tempCom && *tempCom && **tempCom == ':');
279 _tcscpy(buf, *tempCom);
280 endNameList();
281 for (tempCom++; *tempCom; tempCom++) {
282 _tcscpy(buf, *tempCom);
283 addItemToList();
285 if (index == 0) {
286 assignDependents();
288 assignBuildCommands();
293 // doMake()
295 // actions: prints a version message
296 // reads the environment variable MAKEFLAGS
297 // if MAKEFLAGS defined
298 // defines MAKEFLAGS to have that value w/in nmake
299 // sets a flag for each option if MAKEFLAGS defined
300 // else defines the macro MAKEFLAGS to be NULL
301 // parses commandline (adding option letters to MAKEFLAGS)
302 // reads all environment variables
303 // reads tools.ini
304 // reads makefile(s) (if -e flag set, new definitions in
305 // makefile won't override environment variable defs)
306 // prints information if -p flag
307 // processes makefile(s)
308 // prints information if -d flag and not -p flag (using both
309 // is overkill)
311 // In effect, the order for making assignments is (1 = least binding,
312 // 4 = most binding):
314 // 1) TOOLS.INI
315 // 2) environment (if -e flag, makefile)
316 // 3) makefile (if -e flag, environment)
317 // 4) command line
319 // The user can put anything he wants in the MAKEFLAGS environment variable.
320 // I don't check it for illegal flag values, because there are many xmake
321 // flags that we don't support. He shouldn't have to change his MAKEFLAGS
322 // to use nmake. Xmake always puts 'b' in MAKEFLAGS for "backward com-
323 // patibility" (or "botch") for the original Murray Hill version of make.
324 // It doesn't make sense to use -f in MAKEFLAGS, thus it is disallowed.
325 // It also makes little sense to let the default flags be -r, -p, or -d,
326 // so they aren't allowed in MAKEFLAGS, either.
328 // Even though DOS only uses uppercase in environment variables, this
329 // program may be ported to xenix in the future, thus we allow for the
330 // possibility that MAKEFLAGS and commandline options will be in upper
331 // and/or lower case.
333 // modifies: init global flag set if tools.ini is being parsed...
336 doMake(
337 unsigned argc,
338 char *argv[],
339 char *parentBlkPtr // state of parent, restored prior to return
342 int status = 0;
343 char *p;
344 // extern char *makeStr; // the initial make invok name
345 char *makeDir, *curDir;
347 #ifdef DEBUG_ALL
348 printf ("DEBUG: In doMake\n");
349 #endif
351 assert(parentBlkPtr == NULL);
353 // Load built-ins here rather than in main(). Otherwise in a recursive
354 // make, doMake() will initialize rules to some value which has been
355 // freed by sortRules().
357 inlineFileList = (STRINGLIST *)NULL;
358 makeDir = makeString("MAKEDIR");
359 curDir = getCurDir();
360 // Use M_LITERAL flag to prevent nmake from trying to
361 // interpret $ in path as an embedded macro. [DS 14983]
362 defineMacro(makeDir, curDir, M_LITERAL);
364 // TEMPFIX: We are truncating MAKEFLAGS environment variable to its limit
365 // to avoid GP Faults
366 if ((p = getenv("MAKEFLAGS"))) { // but not MAKEFLAGS
367 _tcsncpy(makeflags+10, p, _tcslen(makeflags + 10));
370 // fInheritUserEnv is set to TRUE so that the changes made get inherited
372 fInheritUserEnv = TRUE;
374 // Simply adding global strings to the macro array
375 // causes problems later when you go to free them
376 // from a recursive $(MAKE). Both the macro name
377 // and the macro's value must be created with
378 // makeString.
380 defineMacro(makeString("MAKEFLAGS"), makeString(makeflags+10), M_NON_RESETTABLE|M_ENVIRONMENT_DEF);
382 for (;p && *p; p++) { // set flags in MAKEFLAGS
383 setFlags(*p, TRUE); // TRUE says turn bits ON
386 parseCommandLine(--argc, ++argv); // skip over program name
388 #ifdef DEBUG_ALL
389 printf ("DEBUG: Command Line parsed\n");
390 #endif
392 if (!bannerDisplayed) {
393 displayBanner(); // version number, etc.
396 if (OFF(gFlags, F1_IGNORE_EXTERN_RULES)) { // read tools.ini
397 #ifdef DEBUG_ALL
398 printf ("DEBUG: Read Tools.ini\n");
399 #endif
400 loadBuiltInRules();
401 #ifdef DEBUG_ALL
402 printf ("DEBUG: loadBuiltInRules\n");
403 #endif
404 fName = "tools.ini";
406 if (tagOpen("INIT", fName, makeStr)) {
407 ++line;
408 init = TRUE; // tools.ini being parsed
410 #ifdef DEBUG_ALL
411 printf ("DEBUG: Start Parse\n");
412 #endif
413 parse();
415 #ifdef DEBUG_ALL
416 printf ("DEBUG: Parsed\n");
417 #endif
418 if (fclose(file) == EOF)
419 makeError(0, ERROR_CLOSING_FILE, fName);
423 #ifdef DEBUG_ALL
424 printf ("after tagopen\n");
425 #endif
427 // For XMake Compatibility MAKEFLAGS should always be inherited to the Env
428 // Put copy of makeflags so that the environment can be freed on return
429 // from a recursive make
431 if (PutEnv(makeString(makeflags)) == -1) {
432 makeError(0, OUT_OF_ENV_SPACE);
435 #ifdef DEBUG_ALL
436 printf ("after putenv\n");
437 #endif
439 if (!makeFiles) {
440 useDefaultMakefile(); // if no -f makefile given
443 if (readEnvironmentVars() == -1) {
444 makeError(0, OUT_OF_MEMORY);
446 readMakeFiles(); // read description files
448 #ifdef DEBUG_ALL
449 printf ("DEBUG: Read makefile\n");
450 #endif
452 currentLine = 0; // reset line after done
453 sortRules(); // reading files (for error messages)
455 if (ON(gFlags, F1_PRINT_INFORMATION)) {
456 showMacros();
457 showRules();
458 showTargets();
461 // free buffer used for conditional processing - not required now
462 if (lbufPtr) {
463 FREE(lbufPtr);
466 status = processTree();
468 // We ignore retval from chdir because we cannot do anything if it fails
469 // This accomplishes a 'cd $(MAKEDIR)'.
470 _chdir(curDir);
471 return(status);
475 // filename -- filename part of a name
477 // Scope: Local
479 // Purpose:
480 // A complete file name is of the form <drive:><path><filename><.ext>. This
481 // function returns the filename part of the name.
483 // Input: src -- The complete file name
484 // dst -- filename part of the complete file name
486 // Output: Returns TRUE if src has a filename part & FALSE otherwise
488 // Assumes: That the file name could have either '/' or '\' as path separator.
490 // Notes:
491 // Allocates memory for filename part. Function was rewritten to support OS/2
492 // Ver 1.2 filenames.
495 BOOL
496 filename(
497 const char *src,
498 char **dst
501 char szFilename[_MAX_FNAME]; // The filename part
503 // Split the full pathname to components
504 _splitpath(src, NULL, NULL, szFilename, NULL);
506 // Allocate & copy the filename part to the return string
507 *dst = makeString(szFilename);
509 // Finished
510 return (BOOL) _tcslen(*dst);
514 // readMakeFiles()
516 // actions: walks through the list calling parse on each makefile
517 // resets the line number before parsing each file
518 // removes name of parsed file from list
519 // frees removed element's storage space
521 // modifies: file global file pointer (FILE*)
522 // fName global pointer to file name (char*)
523 // line global line number used and updated by the lexer
524 // init global flag reset for parsing makefiles
525 // ( files other than tools.ini )
526 // makeFiles in main() by modifying contents of local pointer (list)
528 // We keep from fragmenting memory by not allocating and then freeing space
529 // for the (probably few) names in the files and targets lists. Instead
530 // we use the space already allocated for the argv[] vars, and use the space
531 // we alloc for the commandfile vars. The commandfile vars that could be
532 // freed here, but they aren't because we can't tell them from the argv[]
533 // vars. They will be freed at the end of the program.
535 void
536 readMakeFiles(
537 void
540 STRINGLIST *q;
542 for (q = makeFiles; q ; q = q->next) { // for each name in list
543 if ((q->text)[0] == '-' && !(q->text)[1]) {
544 fName = makeString("STDIN");
545 file = stdin;
546 } else {
547 fName = makeString(q->text);
548 if (!(file = FILEOPEN(fName, "rt"))) // open to read, text mode
549 makeError(0, CANT_OPEN_FILE, fName);
550 if (!IsValidMakefile(file))
551 makeError(0, CANT_SUPPORT_UNICODE, fName);
553 line = 0;
554 init = FALSE; // not parsing tools.ini
555 parse();
556 if (file != stdin && fclose(file) == EOF)
557 makeError(0, ERROR_CLOSING_FILE, fName);
560 // free the list of makefiles
561 freeStringList(makeFiles);
565 // readEnvironmentVars - Read in environment variables into Macro table
567 // Scope: Local.
569 // Purpose:
570 // Reads environment variables into the NMAKE macro Table. It walks through envp
571 // using environ making entries in NMAKE's hash table of macros for each string
572 // in the table.
574 // Assumes: That the env contains strings of the form "VAR=value" i.e. '=' present.
576 // Modifies Globals: fInheritUserEnv - set to false.
578 // Uses Globals:
579 // environ - Null terminated table of pointers to environment variable
580 // definitions of the form "name=value" (Std C Runtime variable)
582 // Notes:
583 // If the user specifies "set name=value" as a build command for a target being
584 // built, the change in the environment will not be reflected in nmake's set of
585 // defined variables in the macro table.
588 readEnvironmentVars(
589 void
592 char *macro, *value;
593 char *t;
594 char *envPtr;
595 char *envPtrBase;
597 int cbMultiByte;
598 int cchWideVar;
599 int cchWide;
600 WCHAR *tW;
601 WCHAR *envW = GetEnvironmentStringsW();
602 if (!envW) {
603 return -1;
605 cchWide = 0;
606 cbMultiByte = 1; // need at least the terminating NULL
607 for (tW = envW; *tW; tW+=cchWideVar+1) {
608 cchWideVar = wcslen(tW);
609 cchWide += cchWideVar+1;
610 cbMultiByte += cchWideVar*2+1;
612 envPtrBase = (char *)malloc(cbMultiByte);
613 if (!envPtrBase) {
614 FreeEnvironmentStringsW(envW);
615 return -1;
617 if (WideCharToMultiByte(CP_ACP, 0,
618 envW, cchWide+1,
619 envPtrBase, cbMultiByte,
620 NULL, NULL) == 0) {
621 FreeEnvironmentStringsW(envW);
622 free(envPtrBase);
623 return -1;
625 envPtr = envPtrBase;
627 for (envPtr = envPtrBase;*envPtr; envPtr+=strlen(envPtr)+1) {
628 if ((t = _tcschr(envPtr, '='))) { // should always be TRUE
629 if (!_tcsnicmp(envPtr, "MAKEFLAGS", 8))
630 continue;
631 *t = '\0';
632 // Don't add empty names.
633 if (*envPtr == '\0')
634 continue;
635 // ALLOC: here we make copies of the macro name and value to define
636 macro = _tcsupr(makeString(envPtr));
638 value = makeString(t+1);
639 *t = '=';
640 fInheritUserEnv = (BOOL)FALSE;
641 if (!defineMacro(macro, value, M_ENVIRONMENT_DEF)) {
642 // ALLOC: here we free the copies if they were not added.
643 FREE(macro);
644 FREE(value);
648 FreeEnvironmentStringsW(envW);
649 free(envPtrBase);
650 return 0;
654 // parseCommandLine()
656 // arguments: argc count of arguments in argv vector
657 // argv table of pointers to commandline arguments
659 // actions: reads a command file if necessary
660 // sets switches
661 // defines macros
662 // makes a list of makefiles to read
663 // makes a list of targets to build
665 // modifies: makeFiles in main() by modifying contents of parameter
666 // pointer (list) to STRINGLIST pointer
667 // (makeFiles)
668 // makeTargets in main() by modifying contents of param
669 // pointer (targets) to STRINGLIST pointer
670 // fInheritUserEnv set to TRUE so that user defined changes in the
671 // environment variables get inherited by the Env
673 // nmake doesn't make new copies of command line macro values or environment
674 // variables, but instead uses pointers to the space already allocated.
675 // This can cause problems if the envp, the environment pointer, is accessed
676 // elsewhere in the program (because the vector's strings will contain '\0'
677 // where they used to contain '='). I don't foresee any need for envp[] to
678 // be used elsewhere. Even if we did need to use the environment, we could
679 // access the environ variable or use getenv().
681 // I don't care what the current DOS "switch" character is -- I always
682 // let the user give either.
684 void
685 parseCommandLine(
686 unsigned argc,
687 char *argv[]
690 STRINGLIST *p;
691 char *s;
692 char *t;
693 BOOL fUsage = FALSE;
695 for (; argc; --argc, ++argv) {
696 if (**argv == '@') { // cmdfile
697 readCommandFile((char *) *argv+1);
698 // On Unix, '/' can be used when specifying a fully qualified path
699 } else if (**argv == '-') { // switch
700 s = *argv + 1;
701 if (!_tcsicmp(s, "help")) {
702 fUsage = TRUE;
703 break;
706 // if '-' and '/' specified then ignores it
707 for (; *s; ++s) {
708 if (!_tcsicmp(s, "nologo")) {
709 setFlags(s[2], TRUE);
710 break;
711 } else if (*s == '?') {
712 fUsage = TRUE;
713 break;
714 } else if (*s == 'f' || *s == 'F') {
715 char *mkfl = s+1;
717 //if '/ffoo' then use 'foo'; else use next argument
718 if (!*mkfl && (!--argc || !*++argv || !*(mkfl = *argv))) {
719 makeError(0, CMDLINE_F_NO_FILENAME);
721 p = makeNewStrListElement();
722 p->text = makeString(mkfl);
723 appendItem(&makeFiles, p);
724 break;
725 } else {
726 setFlags(*s, TRUE);
729 } else {
730 if ((s = _tcschr(*argv, '='))) { // macro
731 if (s == *argv) {
732 makeError(0, CMDLINE_NO_MACRONAME); // User has specified "=value"
734 *s = '\0';
735 for (t = s++ - 1; WHITESPACE(*t); --t)
737 *(t+1) = '\0';
738 fInheritUserEnv = (BOOL)TRUE;
739 defineMacro(makeString(*argv+_tcsspn(*argv, " \t")),
740 makeString( s+_tcsspn(s," \t")),
741 M_NON_RESETTABLE);
742 } else {
743 removeTrailChars(*argv);
744 if (**argv) {
745 p = makeNewStrListElement(); // target
746 // use quotes around name if it contains spaces
747 if (_tcschr(*argv, ' ')) {
748 p->text = makeQuotedString(*argv);
750 else {
751 p->text = makeString(*argv); // needs to be on heap [rm]
753 appendItem(&makeTargets, p);
756 *argv = NULL; // so we won't try to free this space
757 } // if processing command file stuff
760 if (fUsage) {
761 usage();
762 exit(0);
767 // useDefaultMakefile -- tries to use the default makefile
769 // Scope:
770 // Local
772 // Purpose:
773 // When no makefile has been specified by the user, set up the default makefile
774 // to be used.
776 // Input:
777 // Output:
778 // Errors/Warnings:
779 // CMDLINE_NO_MAKEFILE -- 'makefile' does not exist & no target specified
781 // Assumes:
782 // Modifies Globals:
783 // makeTargets -- if 'makefile' does not exist then the first target is removed
784 // from this list,
785 // makeFiles -- if 'makefile' does not exist then the first target is attached
786 // to this list.
788 // Uses Globals:
789 // makeTargets -- the list of targets to be made
791 // Notes:
792 // Given a commandline not containing a '-f makefile', this is how NMAKE
793 // behaves --
794 // If ['makefile' exists] then use it as the makefile,
795 // if [(the first target exists and has no extension) or
796 // (if it exists and has an extension for which no inference rule
797 // exists)]
798 // then use it as the makefile.
800 void
801 useDefaultMakefile(
802 void
805 STRINGLIST *p;
806 char *s, *ext;
807 char nameBuf[MAXNAME];
808 struct _finddata_t finddata;
810 if (!_access("makefile", READ)) {
811 // if 'makefile' exists then use it
812 p = makeNewStrListElement();
813 p->text = makeString("makefile");
814 makeFiles = p;
815 } else if (makeTargets) {
816 //check first target
817 s = makeTargets->text;
818 if (_access(s, READ) || // 1st target does not exist
819 ((ext = _tcsrchr(s, '.'))
820 && findRule(nameBuf, s, ext, &finddata))) { //has no ext or inf rule
821 return;
824 p = makeTargets;
825 makeTargets = makeTargets->next; // one less target
826 makeFiles = p; // 1st target is the makefile
827 } else if (OFF(gFlags, F1_PRINT_INFORMATION)) {
828 //if -p and no makefile, simply give information ...
829 makeError(0, CMDLINE_NO_MAKEFILE); // no 'makefile' or target
834 // setFlags()
836 // arguments: line current line number in makefile (or 0
837 // if still parsing commandline)
838 // c letter presumed to be a commandline option
839 // value TRUE if flag should be turned on, FALSE for off
841 // actions: checks to see if c is a valid option-letter
842 // if no, error, halt
843 // if value is TRUE, sets corresponding flag bit
844 // and adds flag letter to MAKEFLAGS macro def
845 // else if flag is resettable, clears corresponding bit
846 // and removes letter from MAKEFLAGS macro def
848 // modifies: flags external resettable-flags
849 // gFlags external non-resettable flags
850 // (MAKEFLAGS nmake internal macrodefs)
852 // Only the flags w/in the "flags" variable can be turned off. Once the
853 // bits in "gFlags" are set, they remain unchanged. The bits in "flags"
854 // are modified via the !CMDSWITCHES directive.
856 void
857 setFlags(
858 char c,
859 BOOL value
862 // Use lexer's line count. If this gets called w/in mkfil, might be from
863 // directive, which never makes it to the parser, so parser's line count
864 // might be out of sync.
866 char d = c;
867 UCHAR arg=0;
868 UCHAR *f;
869 char *s;
870 extern MACRODEF * pMacros;
871 extern STRINGLIST * pValues;
873 f = &flags;
874 switch(c = (char) _totupper(c)) {
875 case 'A':
876 arg = F2_FORCE_BUILD;
877 break;
879 case 'B':
880 fRebuildOnTie = TRUE;
881 return;
883 case 'C':
884 arg = F1_CRYPTIC_OUTPUT;
885 f = &gFlags;
886 bannerDisplayed = TRUE;
887 break;
889 case 'D':
890 arg = F2_DISPLAY_FILE_DATES;
891 break;
893 case 'E':
894 arg = F1_USE_ENVIRON_VARS;
895 f = &gFlags;
896 break;
898 case 'I':
899 arg = F2_IGNORE_EXIT_CODES;
900 break;
902 case 'K':
903 fOptionK = TRUE;
904 return;
906 case 'L':
907 arg = F1_NO_LOGO;
908 f = &gFlags;
909 bannerDisplayed = TRUE;
910 break;
912 case 'N':
913 arg = F2_NO_EXECUTE;
914 break;
916 case 'O':
917 fDescRebuildOrder = TRUE;
918 return;
920 case 'P':
921 arg = F1_PRINT_INFORMATION;
922 f = &gFlags;
923 break;
925 case 'Q':
926 arg = F1_QUESTION_STATUS;
927 f = &gFlags;
928 break;
930 case 'R':
931 arg = F1_IGNORE_EXTERN_RULES;
932 f = &gFlags;
933 break;
935 case 'S':
936 arg = F2_NO_ECHO;
937 break;
939 case 'T':
940 arg = F1_TOUCH_TARGETS;
941 f = &gFlags;
942 break;
944 case 'U':
945 arg = F2_DUMP_INLINE;
946 break;
948 case 'Y':
949 arg = F1_NO_BATCH;
950 f = &gFlags;
951 break;
953 case ' ':
954 return; // recursive make problem
956 default:
957 makeError(0, CMDLINE_BAD_OPTION, d);
960 if (!pMacros) {
961 pMacros = findMacro("MAKEFLAGS");
962 pValues = pMacros->values;
965 if (value) {
966 SET(*f, arg); // set bit in flags variable
967 if (c == 'Q') SET(*f, F1_CRYPTIC_OUTPUT);
968 if (!_tcschr(pValues->text, c)) { // don't want to dup any chars
969 if ((s = _tcschr(pValues->text, ' '))) // append ch to MAKEFLAGS
970 *s = c;
971 if (PutEnv(makeString(makeflags)) == -1) // pValues->text pts into makeflags
972 makeError(line, OUT_OF_ENV_SPACE);
974 } else if (f == &flags
976 // make sure pointer is valid (we can't change gFlags, except if /Z
977 CLEAR(*f, arg);
978 if ((s = _tcschr(pValues->text, c))) // adjust MAKEFLAGS
979 do {
980 *s = *(s+1); // move remaining chars over
981 } while (*(++s));
982 if (PutEnv(makeString(makeflags)) == -1)
983 makeError(line, OUT_OF_ENV_SPACE);
987 // chkPrecious -- handle ^c or ^Break, etc.
989 // Actions: unlink all non-precious files and unrequired scriptFiles
990 // quit with error message (makeError unlinks temp. files)
992 BOOL PALAPI
993 chkPrecious(
994 DWORD CtrlType
997 if (okToDelete &&
998 OFF(flags, F2_NO_EXECUTE) &&
999 OFF(gFlags, F1_TOUCH_TARGETS) &&
1000 dollarAt &&
1001 _access(dollarAt, 0x00) && // existence check
1002 !isPrecious(dollarAt)
1004 if (DeleteFileA(dollarAt) == FALSE)
1005 makeError(line, REMOVED_TARGET, dollarAt);
1007 makeError(0, USER_INTERRUPT);
1008 delScriptFiles();
1010 return TRUE;
1014 UCHAR
1015 isPrecious(
1016 char *p
1019 STRINGLIST *temp;
1021 for (temp = dotPreciousList; temp; temp = temp->next)
1022 if (!_tcsicmp(temp->text, p))
1023 return(1);
1024 return(0);
1027 // delScriptFiles -- deletes script files
1029 // Scope: Global
1031 // Purpose:
1032 // Since script files may be reused in the makefile the script files which have
1033 // NOKEEP action specified are deleted at the end of the make.
1035 // Uses Globals: delList -- the list of script files to be deleted
1037 // Notes:
1038 // We ignore the exit code as a result of a delete because the system will
1039 // inform the user that a delete failed.
1041 void
1042 delScriptFiles(
1043 void
1046 STRINGLIST *del;
1049 for (del = delList; del;del = del->next) {
1050 _unlink(del->text);
1051 if (ON(flags, F2_NO_EXECUTE)) {
1052 printf("\tdel %s\n", del->text);
1053 fflush(stdout);
1059 // removeTrailChars - removes trailing blanks and dots
1061 // Scope: Local.
1063 // Purpose:
1064 // OS/2 1.2 filenames dictate removal of trailing blanks and periods. This
1065 // function removes them from filenames provided to it.
1067 // Input: szFile - name of file
1069 // Notes:
1070 // This function handles Quoted filenames as well. It maintains the quotes if
1071 // they were present. This is basically for OS/2 1.2 filename support.
1073 void
1074 removeTrailChars(
1075 char *szFile
1078 char *t = szFile + _tcslen(szFile) - 1;
1079 BOOL fQuoted = FALSE;
1081 if (*szFile == '"' && *t == '"') {
1082 // Quoted so set flag
1083 t--;
1084 fQuoted = TRUE;
1087 // Scan backwards for trailing characters
1088 while (t > szFile && (*t == ' ' || *t == '.'))
1089 t--;
1091 // t points to last non-trailing character. It it was quited, add quotes
1092 // to the end
1093 if (fQuoted)
1094 *++t = '"';
1096 t[1] = '\0';